package aceim.protocol.snuk182.icq.inner; import java.util.ArrayList; import java.util.List; import aceim.protocol.snuk182.icq.inner.dataentity.Flap; import aceim.protocol.snuk182.icq.inner.dataentity.Snac; import aceim.protocol.snuk182.icq.inner.dataentity.TLV; import aceim.protocol.snuk182.icq.utils.ProtocolUtils; public final class ICQDataParser { public List<Flap> parseFlaps(byte[] in) throws ICQException{ List<Flap> flaps = new ArrayList<Flap>(); if (in == null) { return flaps; } if (in.length <6){ throw new ICQException("Error - broken FLAP"); } int pos = 0; while (pos<in.length){ int tailLength = 6+ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(in, pos+4)); //System.out.println("1 flap length:"+tailLength); if (tailLength != 0){ byte[] tailData = new byte[tailLength]; System.arraycopy(in, pos+0, tailData, 0, tailLength); Flap flap = parseFlap(tailData); if (flap!=null){ flaps.add(flap); } } pos+=tailLength; } return flaps; } public Flap parseFlap(byte[] in) throws ICQException{ if (in == null) { throw new ICQException("Error - no FLAP data!"); } if (in[0] != 0x2a){ throw new ICQException("Error - not a FLAP:"+in); } Flap flap = new Flap(); flap.channel = in[1]; flap.sequenceNumber = (short) (ProtocolUtils.bytes2ShortBE(in, 2)); int tailLength = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(in, 4)); //System.out.println("snac length:"+tailLength); if (tailLength > 0 && !(in[1]==0x1 && tailLength == 4)){ byte[] tailData; if (in[1] == 0x01){ tailData = new byte[tailLength-4]; System.arraycopy(in, 10, tailData, 0, tailLength-4); } else { tailData = new byte[tailLength]; System.arraycopy(in, 6, tailData, 0, tailLength); } if (in[1] == 0x02) { flap.data = parseSnac(tailData); } else { flap.tlvData = parseTLV(tailData); } } return flap; } public Snac parseSnac(byte[] in) throws ICQException{ //System.out.println(" parse snac -> "+ProtocolUtils.getSpacedHexString(in)); if (in == null){ throw new ICQException("Error - no SNAC data!"); } if (in.length<10){ throw new ICQException("Error - SNAC data corrupted"+in); } Snac snac = new Snac(); snac.serviceId = (short) ((in[0]<<8)+in[1]); snac.subtypeId = (short) ((in[2]<<8)+in[3]); snac.hFlag = in[4]; snac.lFlag = in[5]; snac.requestId = (in[6]<<24)+(in[7]<<16)+(in[8]<<8)+(in[9]); if (in.length > 10){ int govno = snac.hFlag&0x80; short dataToSkip = 0; if (govno>0){ dataToSkip = (short) (ProtocolUtils.bytes2ShortBE(in, 10)+2); } int tailLength = in.length - 10 - dataToSkip; snac.plainData = new byte[tailLength]; System.arraycopy(in, 10+dataToSkip, snac.plainData, 0, tailLength); //snac.setData(parseTLV(snac.getPlainData())); } /*if (incompleteSnac !=null && incompleteSnac.getServiceId()==snac.getServiceId() && incompleteSnac.getSubtypeId()==incompleteSnac.getSubtypeId()){ byte[] completeSnac = new byte[incompleteSnac.getPlainData().length+snac.getPlainData().length]; System.arraycopy(incompleteSnac.getPlainData(), 0, completeSnac, 0, incompleteSnac.getPlainData().length); System.arraycopy(snac.getPlainData(), 0, completeSnac, incompleteSnac.getPlainData().length, snac.getPlainData().length); snac.setPlainData(completeSnac); System.out.println(" full snac -> "+ProtocolUtils.getSpacedHexString(completeSnac)); } if (snac.getlFlag()>0){ incompleteSnac = snac; } else { incompleteSnac = null; }*/ return snac; } public TLV[] parseTLV(byte[] in) throws ICQException{ return parseTLV(in, -1); } public TLV[] parseTLV(byte[] in, int tlvCount) throws ICQException{ //System.out.println(" parse tlv -> "+ProtocolUtils.getSpacedHexString(in)); if (in == null){ throw new ICQException("Error - no TLV data"); } if (in.length < 1){ return new TLV[0]; } if (in.length<4){ throw new ICQException("Error - TLV data corrupted"); } List<TLV> tlvs = new ArrayList<TLV>(); for (int i=0; i<in.length; i++){ if (tlvCount>-1 && i==tlvCount){ break; } TLV tlv = new TLV(); int type = (in[i]<<8)+(in[++i]&0xff); //tlv.setType(Utils.unsignedShort2Int((short) ()); tlv.type = type; //tlv.setLength((short) ((in[++i]<<8)+in[++i])); int length = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(in, ++i)); i++; if (length>0 && in.length>4){ byte[] tailData = new byte[length]; System.arraycopy(in, ++i, tailData, 0, length); tlv.value = tailData; i+=length-1; } //System.out.println(" parsed "+type+"-"+length+"bytes"); tlvs.add(tlv); } TLV[] array = new TLV[tlvs.size()]; for (int i=0;i<tlvs.size();i++){ array[i] = tlvs.get(i); } return array;//(TLV[]) tlvs.toArray(); } public byte[] flaps2Bytes(Flap[] flaps) throws ICQException{ if (flaps == null){ throw new ICQException("Error - flaps is null"); } if (flaps.length == 1){ return flap2Bytes(flaps[0]); } int length = 0; List<byte[]> bytes = new ArrayList<byte[]>(); for (int i=0; i<flaps.length; i++){ if (flaps[i]==null){ continue; } byte[] out = flap2Bytes(flaps[i]); length += out.length; bytes.add(out); } byte[] out = new byte[length]; int pos = 0; for (int i=0; i<bytes.size(); i++){ System.arraycopy(bytes.get(i), 0, out, pos, bytes.get(i).length); pos+=bytes.get(i).length; } return out; } public byte[] flap2Bytes(Flap flap) throws ICQException{ if (flap == null){ throw new ICQException("Error - flap is null"); } byte[] snacData = null; byte[] tlvData = null; if (flap.data != null){ snacData = snac2Bytes(flap.data); } if (flap.tlvData != null){ tlvData = tlvs2Bytes(flap.tlvData); } short dataLength = (short) ((snacData!=null?snacData.length:0)+(tlvData!=null?tlvData.length:0)); byte[] out = new byte[1+1+2+2+dataLength]; out[0] = 0x2a; out[1] = flap.channel; byte[] buf = ProtocolUtils.short2ByteBE(flap.sequenceNumber); System.arraycopy(buf, 0, out, 2, buf.length); buf = ProtocolUtils.short2ByteBE(dataLength); System.arraycopy(buf, 0, out, 4, buf.length); if (snacData!=null){ System.arraycopy(snacData, 0, out, 6, snacData.length); } if (tlvData!=null){ if (snacData==null){ System.arraycopy(tlvData, 0, out, 6, tlvData.length); } else { System.arraycopy(snacData, 0, out, 6+snacData.length, snacData.length); } } return out; } public byte[] snac2Bytes(Snac snac) throws ICQException{ if (snac == null){ throw new ICQException("Error - snac is null"); } int length = 2+2+2+4; byte[] tlvData = null; if (snac.data!=null){ tlvData = tlvs2Bytes(snac.data); length += tlvData.length; } if (snac.plainData!=null){ length += snac.plainData.length; } byte[] out = new byte[length]; byte[] buf = ProtocolUtils.short2ByteBE(snac.getServiceId()); System.arraycopy(buf, 0, out, 0, buf.length); buf = ProtocolUtils.short2ByteBE(snac.subtypeId); System.arraycopy(buf, 0, out, 2, buf.length); buf = ProtocolUtils.int2ByteBE(snac.requestId); out[4] = snac.hFlag; out[5] = snac.lFlag; System.arraycopy(buf, 0, out, 6, buf.length); int pos = 10; if (snac.plainData!=null){ System.arraycopy(snac.plainData, 0, out, pos, snac.plainData.length); pos+=snac.plainData.length; } if (tlvData!=null){ System.arraycopy(tlvData, 0, out, pos, tlvData.length); pos+=tlvData.length; } return out; } public byte[] tlvs2Bytes(TLV[] tlvs){ if (tlvs == null){ return new byte[0]; } List<byte[]> list = new ArrayList<byte[]>(tlvs.length); int lengthAll = 0; for (int i=0; i<tlvs.length; i++){ if (tlvs[i].value==null){ tlvs[i].value = new byte[0]; } int length = 2+tlvs[i].value.length; if (tlvs[i].type != 0x0){//authrequest length += 2; } byte[] bytes = new byte[length]; byte[] buf = ProtocolUtils.short2ByteBE((short) tlvs[i].type); System.arraycopy(buf, 0, bytes, 0, buf.length); int dataOffset = 2; if (tlvs[i].type != 0x0){//authrequest buf = ProtocolUtils.short2ByteBE((short) tlvs[i].value.length); System.arraycopy(buf, 0, bytes, 2, buf.length); dataOffset += 2; } if (tlvs[i].value.length>0){ System.arraycopy(tlvs[i].value, 0, bytes, dataOffset, tlvs[i].value.length); } lengthAll+=length; list.add(bytes); } byte[] out = new byte[lengthAll]; int bytepos = 0; for (byte[] item:list){ System.arraycopy(item, 0, out, bytepos, item.length); bytepos += item.length; } return out; } }